package com.jiang.firefly;

import com.jiang.operator.BlockChain;

public class Particle {
    int n;						//粒子数量
    ParticleState[] p;			//粒子数组
    ParticleState[] v;			//速度数组，速度也有两个方向的速度
    ParticleState[] pbest;		//粒子最优解
    public ParticleState gbest;		//全局最优解
    double vmax;				//最大速度
    int c1,c2;					//学习参数
    public static int dim;
    public static String uLocation = null;
    public static double uDataSize;

    //适应函数
    public double f(double[] args1, double[][] args2) {
        //选择道德
        int power = 1000;
        double sum1 = 0,sum2 = 0;
        for(int i = 0;i < args1.length;i++){
            sum1 += (args1[i]) * (BlockChain.canNode.get(i).getFdc(uDataSize));//这里是存储成本
        }
        for(int i = 0;i < args2.length;i++){
            for(int j = 0;j < args2[i].length;j++){
                //这里有访问成本以及采集成本
                sum2 += args2[i][j] * (BlockChain.canNode.get(i).getRdc(BlockChain.nodeList.get(j)) + BlockChain.nodeList.get(i).getUE(uLocation));
            }
        }
        return power*sum1+sum2;
    }

    public void fitnessFunction() {
        for(int i = 0; i< n; i++) {
            //计算每个粒子当前位置的适应度
            p[i].f = f(p[i].getDims1(), p[i].getDims2());
        }
    }

    //初始化
    public void init() {
        n = 100;//100个粒子
        p = new ParticleState[n];//n个粒子的位置
        v = new ParticleState[n];//n个粒子的速度
        pbest = new ParticleState[n];//各个粒子的最优解
        gbest = new ParticleState(dim);//全局最优解
        c1=3;
        c2=2;
        vmax = 0.3;//最大速度

        for(int i = 0;i < n;i++) {
            //初始化余切初始化
            //p[i]=new ParticleState(dim);
            p[i]=new ParticleState(dim);//坐标初始化，随机初始化
            v[i]=new ParticleState(dim, vmax);//速度的范围内初始化
        }

        fitnessFunction();//计算各个粒子的适应度，也就是目的函数

        //初始化粒子与集群的最优值，集群的最优值赋值为整数最小值
        gbest.f = Integer.MAX_VALUE;
        for(int i = 0;i < n;i++) {
            pbest[i] = p[i].clone();//粒子的最优值初始化为初始化各粒子位置
            if(p[i].f < gbest.f) {
                gbest = p[i].clone();//再对全局最优值进行更新，伺机替换
            }
        }
        System.out.println("初始最优值：" +gbest+" "+" "+gbest.f);
    }

    //粒子群算法	max-迭代次数
    public void PSO(int max) {
        for(int i = 0;i < max;i++) {
            double w = 0.3;//惯性权重
            for(int j = 0;j < n;j++) {
                //更新粒子速度
                double[] newV = new double[dim];
                double[][] newV2 = new double[dim][dim];
                for(int k = 0;k < dim;k++) {
                    newV[k]=w*v[j].getDims1()[k]+c1*Math.random()*(pbest[j].getDims1()[k]-p[j].getDims1()[k])+
                            c2*Math.random()*(gbest.getDims1()[k]-p[j].getDims1()[k]);
                    //注意调节学习的最大步长
                }
                for(int k = 0;k < dim;k++) {
                    for(int t = 0;t < dim;t++){
                        newV2[k][t]=w*v[j].getDims2()[k][t]+c1*Math.random()*(pbest[j].getDims2()[k][t]-p[j].getDims2()[k][t])+
                                c2*Math.random()*(gbest.getDims2()[k][t]-p[j].getDims2()[k][t]);
                    }
                    //注意调节学习的最大步长
                }
                //c1、c2作为学习因子，其实就是调整粒子的当前最好位置以及全局最优位置对下次的速度的影响大小
                //w作为惯性系数，也就是上一次速度的影响
                for(int k = 0;k < dim;k++) {
                    //如果计算出的速度过大，则限制为该最大速度
                    if(Math.abs(newV[k]) > vmax) {
                        if(newV[k] > 0) {
                            newV[k] = vmax;
                        }
                        else {
                            newV[k] = -vmax;
                        }
                    }
                    for(int t = 0;t < dim;t++){
                        if(Math.abs(newV2[k][t]) > vmax) {
                            if(newV2[k][t] > 0) {
                                newV2[k][t] = vmax;
                            }
                            else {
                                newV2[k][t] = -vmax;
                            }
                        }
                    }
                }
                v[j].setDims1(newV);;//修改该粒子的速度
                v[j].setDims2(newV2);
                //更新粒子的位置
                p[j].add(v[j].getDims1(), v[j].getDims2());//再更改位置，就是原本的位移加上速度
            }
            fitnessFunction();//全部粒子计算之后，再计算适应度函数
            //更新个体极值和群体极值
            for(int j = 0;j < n;j++) {
                if(p[j].f < pbest[j].f) {
                    pbest[j] = p[j].clone();//再更新粒子的最优
                }
                if(p[j].f < gbest.f) {
                    gbest = p[j].clone();//更新全局最优
                }
            }
            System.out.println("==="+i+"==="+gbest);
        }
        //上述迭代200次
    }
}
